package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.tianji.common.constants.MqConstants.Key.WRITE_REPLY;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author xzh
 * @since 2024-03-14
 */
@Service
@AllArgsConstructor(onConstructor_ = {@Lazy})
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    private final UserClient userClient;
    private final InteractionQuestionMapper questionMapper;
    private final RemarkClient remarkClient;
    private final RabbitMqHelper mqHelper;


    /**
     * 获取问题信息
     *
     * @param id
     * @param latestAnswerId
     * @return
     */
    @Override
    public QuestionVO getQuestionByAnswerId(Long id, Long latestAnswerId) {
        InteractionReply reply = lambdaQuery()
                .eq(InteractionReply::getAnswerId, latestAnswerId)
                .eq(InteractionReply::getQuestionId, id)
                .eq(InteractionReply::getHidden, false)
                .eq(InteractionReply::getAnonymity, false)
                .last("limt 1")
                .one();
        if (reply == null) {
            return null;
        }
        UserDTO userDTO = userClient.queryUserById(reply.getTargetUserId());
        QuestionVO vo = new QuestionVO();
        vo.setLatestReplyContent(reply.getContent());
        vo.setLatestReplyUser(userDTO.getName());
        return vo;
    }

    /**
     * 根据问题id删除相关回复
     *
     * @param id
     * @return
     */
    @Override
    public boolean deleteRactionsByQuestionId(Long id) {
        QueryWrapper<InteractionReply> queryWrapper = new QueryWrapper<InteractionReply>()
                .eq("question_id", id);
        return remove(queryWrapper);
    }

    /**
     * 新增回答或评论
     *
     * @param replyDTO
     */
    @Override
    @Transactional

    public void saveReply(ReplyDTO replyDTO) {
        //获得评论用户id
        Long userId = UserContext.getUser();
        //转换 添加
        InteractionReply reply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        reply.setUserId(userId);
        LocalDateTime now = LocalDateTime.now();
        reply.setCreateTime(now);
        reply.setUpdateTime(now);
        reply.setLikedTimes(0);
        //若answerId为null则点赞评论都为0 若不为空则answerId评论量+1
        //判断是否为空answerId targetReplyId,若为空则这条回复为回答问题
        if (reply.getAnswerId() != null && reply.getTargetReplyId() != null) {

            InteractionReply reply1 = lambdaQuery().eq(InteractionReply::getId, reply.getAnswerId()).one();
            boolean update = lambdaUpdate().eq(InteractionReply::getId, reply.getAnswerId())
                    .set(InteractionReply::getReplyTimes, reply1.getReplyTimes() + 1)
                    .update();
            if (!update) {
                throw new DbException("增加评论数失败");
            }
        } else {
            reply.setReplyTimes(0);
        }
        //新增评论
        boolean save = save(reply);
        if (!save) {
            throw new DbException("增加评论或回复失败");
        }

        //Question表操作
        // 若为回答问题 则更新最近回答的id
        if (reply.getAnswerId() == null && reply.getTargetReplyId() == null) {
            //获得评论
            InteractionReply one = lambdaQuery().eq(InteractionReply::getUserId, userId)
                    .eq(InteractionReply::getCreateTime, now)
                    .eq(InteractionReply::getQuestionId, reply.getQuestionId())
                    .one();
            //获得问题对象 实体
            InteractionQuestion question = questionMapper.selectById(reply.getQuestionId());
            question.setLatestAnswerId(one.getId());
            int i = question.getAnswerTimes() + 1;
            question.setAnswerTimes(i);
            // 判断是不是学生
            if (replyDTO.getIsStudent()) {
                question.setStatus(0);

                //逻辑 : 只给学生增加积分 老师不增加 发送Mq异步通知  +5分 上限20
                String key=WRITE_REPLY;
                mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,key,userId);
            }
            // 更新问题数据
            questionMapper.updateById(question);
        }
    }

    /**
     * 分页查询回答或评论
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<ReplyVO> replyQueryPage(ReplyPageQuery query) {
        // 1.判断是回答分页查询/评论分页查询
        Page<InteractionReply> page = lambdaQuery()
                .eq(query.getQuestionId() != null, InteractionReply::getQuestionId, query.getQuestionId())
                .eq(query.getAnswerId() != null, InteractionReply::getAnswerId, query.getAnswerId())
                .eq(InteractionReply::getHidden, false)
                .page(query.toMpPage("liked_times", false));
        // 2.获取页面资源
        List<InteractionReply> records = page.getRecords();
        // 2.2健壮性判断
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //3.1获得当前回复者的id集合
        Set<Long> userIds = records.stream().map(InteractionReply::getUserId).collect(Collectors.toSet());
        //3.2获得用户昵称 头像 职业
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = null;
        if (CollUtils.isNotEmpty(userDTOS)) {
            userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));
        }

        //3.3获得目标用户的id集合  可能为空
        Set<Long> targeIds = records.stream().map(InteractionReply::getTargetUserId).collect(Collectors.toSet());

        //3.4健壮性判断
        Map<Long, String> targeName = null;
        if (CollUtils.isNotEmpty(targeIds)) {
            //3.5获得目标用户的昵称
            List<UserDTO> targeDtos = userClient.queryUserByIds(targeIds);
            if (CollUtils.isNotEmpty(targeDtos)) {
                targeName = targeDtos.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
            }
        }
        //3.5 获得查询的所有评论的id 不可能为空
        List<Long> listReplyIds = records.stream()
                .map(InteractionReply::getId).collect(Collectors.toList());

        //循环遍历  封装
        List<ReplyVO> list = new ArrayList<>(records.size());
        for (InteractionReply reply : records) {
            //拷贝
            ReplyVO vo = BeanUtils.copyBean(reply, ReplyVO.class);

            //判断用户是否匿名评论
            if (!reply.getAnonymity()) {
                //不是匿名评论则封装昵称职位
                if (userMap != null) {
                    vo.setUserName(userMap.get(reply.getUserId()).getName());
                    vo.setUserType(userMap.get(reply.getUserId()).getType());
                    //判断用户是不是回答问题
                    if (reply.getTargetReplyId() == null && reply.getAnswerId() == null) {
                        //是回答问题则封装头像
                        vo.setUserIcon(userMap.get(reply.getUserId()).getIcon());
                    }
                }
            }

            //判断有无目标用户
            if (reply.getTargetReplyId() != null) {
                //判断目标用户是不是匿名评论
                InteractionReply one = lambdaQuery().eq(InteractionReply::getId, reply.getTargetReplyId()).one();
                //不是匿名评论则封装目标用户昵称
                if (one!=null&&!one.getAnonymity()) {
                    if (targeName != null) {
                        vo.setTargetUserName(targeName.get(reply.getTargetUserId()));
                    }
                }
            }

            // 逻辑 如果新增成功说明用户没有点过赞  失败则点过
            vo.setLiked(false);
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    /**
     * 管理端用户评论分页查询
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<ReplyVO> adminReplyQueryPage(ReplyPageQuery query) {


        // 1.判断是回答分页查询/评论分页查询
        Page<InteractionReply> page = lambdaQuery()
                .eq(query.getQuestionId() != null, InteractionReply::getQuestionId, query.getQuestionId())
                .eq(query.getAnswerId() != null, InteractionReply::getAnswerId, query.getAnswerId())
                .page(query.toMpPage("liked_times", false));
        // 2.获取页面资源
        List<InteractionReply> records = page.getRecords();
        // 2.2健壮性判断
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //3.1获得当前回复者的id集合
        Set<Long> userIds = records.stream().map(InteractionReply::getUserId).collect(Collectors.toSet());
        //3.2获得用户昵称 头像 职业
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = null;
        if (CollUtils.isNotEmpty(userDTOS)) {
            userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));
        }

        //3.3获得目标用户的id集合  可能为空
        Set<Long> targeIds = records.stream().map(InteractionReply::getTargetUserId).collect(Collectors.toSet());

        //3.4健壮性判断
        Map<Long, String> targeName = null;
        if (CollUtils.isNotEmpty(targeIds)) {
            //3.5获得目标用户的昵称
            List<UserDTO> targeDtos = userClient.queryUserByIds(targeIds);
            if (CollUtils.isNotEmpty(targeDtos)) {
                targeName = targeDtos.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
            }
        }
        //3.5 获得查询的所有评论的id 不可能为空
        List<Long> listReplyIds = records.stream()
                .map(InteractionReply::getId).collect(Collectors.toList());
        //3.5.2查询出用户点赞的评论id
//        Set<Long> likedIds = remarkClient.isBizLiked(listReplyIds);
        //循环遍历  封装
        List<ReplyVO> list = new ArrayList<>(records.size());
        for (InteractionReply reply : records) {
            //拷贝
            ReplyVO vo = BeanUtils.copyBean(reply, ReplyVO.class);

            //封装昵称职位
            if (userMap != null) {
                vo.setUserName(userMap.get(reply.getUserId()).getName());
                vo.setUserType(userMap.get(reply.getUserId()).getType());
                //判断用户是不是回答问题
                if (reply.getTargetReplyId() == null && reply.getAnswerId() == null) {
                    //是回答问题则封装头像
                    vo.setUserIcon(userMap.get(reply.getUserId()).getIcon());
                }
            }

            //判断有无目标用户
            if (reply.getTargetReplyId() != null) {
//                InteractionReply one = lambdaQuery().eq(InteractionReply::getId, reply.getTargetReplyId()).one();
                //封装目标用户昵称
                if (targeName != null) {
                    vo.setTargetUserName(targeName.get(reply.getTargetUserId()));
                }
            }

            //查询用户对这条评论有没有点赞 //
//            boolean success = likedIds.add(reply.getId());
            // 逻辑 如果新增成功说明用户没有点过赞  失败则点过
            vo.setLiked(false);
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    /**
     * 管理端修改评论状态 是否隐藏
     *
     * @param id
     * @param hidden
     */
    @Override
    public void adminUpdateReplyHidden(Long id, Boolean hidden) {
        // 如果隐藏的是回复 则只隐藏自己
        lambdaUpdate().eq(InteractionReply::getId, id)
                .set(InteractionReply::getHidden, hidden)
                .update();
        
        // 如果隐藏的是回答 则有关这条回答的都隐藏
        lambdaUpdate().eq(InteractionReply::getAnswerId, id)
                .set(InteractionReply::getHidden, hidden)
                .update();

        // 如果隐藏的是评论 则隐藏自己与回复
        lambdaUpdate().eq(InteractionReply::getTargetReplyId, id)
                .set(InteractionReply::getHidden, hidden)
                .update();
    }
}

